package demo4;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
/**
 * for graph execrise 4-7
 */
public class GraphDemo {
    public Graph makeUpGraph(){
        return new Graph();
    }
    public Project makeUpProject(String name){
        return new Project(name);
    }
    @Setter
    @Getter
    public class Graph{
        ArrayList<Project> project = new ArrayList<Project>();
        HashMap<String, Project> hashMap = new HashMap<String, Project>();
        public void addEdge(String startName,String endName){
            hashMap.get(endName).addNeighbor(hashMap.get(startName));
        }
        public ArrayList<Project> buildGraph(String[] projects,String[][] dependence){
            //
            Arrays.stream(projects).forEach(p->{
                Project project = new Project(p);
                this.project.add(project);
                hashMap.put(p,project);
            });

            /**
             e,f
             a,b
             */
            for (int i = 0; i < dependence.length ; i++) {
                for (int j = 0; j < 1; j++) {
                    addEdge(dependence[i][j],dependence[i][j+1]);
                }
            }
            return project;

        }

    }
    @NoArgsConstructor
    @Getter
    @Setter
    public class Project{
        ArrayList<Project> children = new ArrayList<Project>();
        HashMap<String, Project> hashMap = new HashMap<String, Project>();
        private int dependence;
        private String name;
        public Project(String name){this.name=name;}

        public void addNeighbor(Project project){

            if(!project.hashMap.containsKey(this.getName())) {
                project.children.add(this);
                project.hashMap.put(this.getName(), project);
                this.dependence++;
            }

        }
        public void increamentDependence(){
            dependence++;
        }
        public void decreamnetDependence(){
            dependence--;
        }
    }
    public int addNoDependent(Project[] order,ArrayList<Project> list,int offset){
        for (Project project:list){
            if(project.dependence==0){
                order[offset++]=project;
            }
        }
        return offset;

    }
    public Project[] orderProjects(ArrayList<Project> list){
        Project[] order = new Project[list.size()];
        int endofList = addNoDependent(order,list,0);
        int toBeProcessed =0;
        Project current=null;
        // order[2]=a order[3]=b
        //toBeProcessed =4
        while (toBeProcessed < order.length){
            current=order[toBeProcessed];
            if(current==null){return null;}
            ArrayList<Project> childs = current.getChildren();
            //
            for (Project children : childs) {
                children.decreamnetDependence();
            }

            endofList = addNoDependent(order,childs,endofList);
            toBeProcessed++;
        }
        return order;
    }

    public String listToString(Project[] projects){
        StringBuilder sb =new StringBuilder();
        Arrays.stream(projects).forEach(project -> {
            sb.append(project.getName()).append(",");
        });
        return sb.toString();
    }
    public Project[] findBuildOrder(String[] projects,String[][] dependence){
        ArrayList<Project> projects1 = new Graph().buildGraph(projects,dependence);
        Project[] order = orderProjects(projects1);
        return order;
    }


}
